package view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.swing.JLabel;

import logic.Grass;
import logic.Duck;
import logic.Field;
import logic.FieldStats;
import logic.Fox;
import logic.Hunter;
import logic.Rabbit;
import logic.Simulator;
import logic.Explosion;

    /**
     * Provide a graphical view of a rectangular field. This is 
     * a nested class (a class defined inside a class) which
     * defines a custom component for the user interface. This
     * component displays the field.
     * This is rather advanced GUI stuff - you can ignore this 
     * for your project if you like.
     */
    public class FieldView extends AbstractView
    {
        private final int GRID_VIEW_SCALING_FACTOR = 6;

        private int gridWidth, gridHeight;
        private int xScale, yScale;
        Dimension size;
        private Graphics g;
        private Image fieldImage;
        
        private final String STEP_PREFIX = "Step: ";
        private final String POPULATION_PREFIX = "Population: ";
        private JLabel stepLabel, population;
        
        // Colors used for empty locations.
        private static final Color EMPTY_COLOR = Color.white;

        // Color used for objects that have no defined color.
        private static final Color UNKNOWN_COLOR = Color.gray;
        // A map for storing colors for participants in the simulation
        private Map<Class, Color> colors;
        // A statistics object computing and storing simulation information
        private FieldStats stats;
        /**
         * Create a new FieldView component.
         */
        public FieldView(Simulator simulator)
        {
            super(simulator);
            
            stats = simulator.getStats();
            colors = new LinkedHashMap<Class, Color>();


            stepLabel = new JLabel(STEP_PREFIX + simulator.getStep(), JLabel.CENTER);
            population = new JLabel(POPULATION_PREFIX, JLabel.CENTER);
            setColor(Rabbit.class, Color.orange);
            setColor(Fox.class, Color.blue);
            setColor(Duck.class, Color.red);
            setColor(Hunter.class, Color.black);
            setColor(Grass.class, Color.green);
            setColor(Explosion.class, Color.cyan);
            setLocation(100, 50);
            
        	gridHeight = getModel().getDepth();
            gridWidth = getModel().getWidth();
            size = new Dimension(0, 0);
        }

        /**
         * Tell the GUI manager how big we would like it to be.
         */
        public Dimension getPreferredSize()
        {
            return new Dimension(gridWidth * GRID_VIEW_SCALING_FACTOR,
                                 gridHeight * GRID_VIEW_SCALING_FACTOR);
        }

        /**
         * Prepare for a new round of painting. Since the component
         * may be resized, compute the scaling factor again.
         */
        public void preparePaint()
        {
            if(! size.equals(getSize())) {  // if the size has changed...
                size = getSize();
                fieldImage = createImage(size.width, size.height);
                g = fieldImage.getGraphics();

                xScale = size.width / gridWidth;
                if(xScale < 1) {
                    xScale = GRID_VIEW_SCALING_FACTOR;
                }
                yScale = size.height / gridHeight;
                if(yScale < 1) {
                    yScale = GRID_VIEW_SCALING_FACTOR;
                }
            }
        }
        
        /**
         * Paint on grid location on this field in a given color.
         */
        public void drawMark(int x, int y, Color color)
        {
            g.setColor(color);
            g.fillRect(x * xScale, y * yScale, xScale-1, yScale-1);
        }

        /**
         * The field view component needs to be redisplayed. Copy the
         * internal image to screen.
         */
        public void paintComponent(Graphics g)
        {
        	g.setColor(new Color(238,238,238));
			Dimension d=getSize();
			g.fillRect(0,0,d.width,d.height);
        	if(fieldImage != null) {
                Dimension currentSize = getSize();
                if(size.equals(currentSize)) {
                    g.drawImage(fieldImage, 0, 0, null);
                }
                else {
                    // Rescale the previous image.
                    g.drawImage(fieldImage, 0, 0, currentSize.width, currentSize.height, null);
                }
            }
        }
        /**
         * Define a color to be used for a given class of actor.
         * @param actorClass The actor's Class object.
         * @param color The color to be used for the given class.
         */
        public void setColor(Class actorClass, Color color)
        {
            colors.put(actorClass, color);
        }
        
        /**
         * @return The color to be used for a given class of actor.
         */
        private Color getColor(Class actorClass)
        {
            Color col = colors.get(actorClass);
            if(col == null) {
                // no color defined for this class
                return UNKNOWN_COLOR;
            }
            else {
                return col;
            }
        }
        
        /**
         * Show the current status of the field.
         * @param step Which iteration step it is.
         * @param field The field whose status is to be displayed.
         */
        public void showStatus(int step, Field field)
        {
            if(!isVisible()) {
                setVisible(true);
            }
                
            stepLabel.setText(STEP_PREFIX + step);
            stats.reset();
            
            preparePaint();

            for(int row = 0; row < field.getDepth(); row++) {
                for(int col = 0; col < field.getWidth(); col++) {
                    Object actor = field.getObjectAt(row, col);
                    if(actor != null) {
                        stats.incrementCount(actor.getClass());
                        drawMark(col, row, getColor(actor.getClass()));
                    }
                    else {
                        drawMark(col, row, EMPTY_COLOR);
                    }
                }
            }
            stats.countFinished();

            population.setText(POPULATION_PREFIX + stats.getPopulationDetails(field));
            repaint();
        }
    
    /**
     * updates the view to the new numbers and repaints the view
     */
        public void updateView() {
        population.setText(POPULATION_PREFIX + stats.getPopulationDetails(getModel().getField()));
        stepLabel.setText(STEP_PREFIX + getModel().getStep());
        showStatus(getModel().getStep(), getModel().getField());
		repaint();
	}
    /**
     * Determine whether the simulation should continue to run.
     * @return true If there is more than one species alive.
     */
    public boolean isViable(Field field)
    {
        return stats.isViable(field);
    }
   
    /**
     * gives the population label
     * @return the population label
     */
    public JLabel getPopulationLabel()
    {
    	return population;
    }
    
    /**
     * gives the steplabel
     * @return the steplabel
     */
    public JLabel getStepLabel()
    {
    	return stepLabel;
    }
    
}